package partner

import (
	"github.com/fsnotify/fsnotify"
	"github.com/spf13/cast"
	"github.com/spf13/viper"
	_ "github.com/spf13/viper/remote"
)

type Config struct {
	V *viper.Viper
}

func NewConfig(onChange func(e fsnotify.Event)) *Config {
	v := viper.New()
	v.OnConfigChange(onChange)
	return &Config{v}
}

func (c *Config) LoadFromFile(filePath, fileType string) error {
	c.V.SetConfigFile(filePath)
	c.V.SetConfigType(fileType)
	if err := c.V.ReadInConfig(); err != nil {
		return err
	}
	c.V.WatchConfig()
	return nil
}

func (c *Config) LoadFromRemote(provider, endpoint, path, cType string) error {
	if err := c.V.AddRemoteProvider(provider, endpoint, path); err != nil {
		return err
	}
	c.V.SetConfigType(cType)
	if err := c.V.ReadRemoteConfig(); err != nil {
		return err
	}
	if err := c.V.WatchRemoteConfig(); err != nil {
		return err
	}
	return nil
}

func (c *Config) SetDefault(key string, val any) {
	c.V.SetDefault(key, val)
}

func (c *Config) Get(key string) any {
	return c.V.Get(key)
}

func (c *Config) GetDefault(key string, defVal any) any {
	if r := c.Get(key); r != nil {
		return r
	} else {
		return defVal
	}
}

func (c *Config) GetAll() map[string]any {
	return c.V.AllSettings()
}

func (c *Config) GetString(key string) string {
	return c.V.GetString(key)
}

func (c *Config) GetStringDefault(key string, defVal string) string {
	return cast.ToString(c.GetDefault(key, defVal))
}

func (c *Config) GetBool(key string) bool {
	return c.V.GetBool(key)
}

func (c *Config) GetBoolDefault(key string, defVal bool) bool {
	return cast.ToBool(c.GetDefault(key, defVal))
}

func (c *Config) GetFloat64(key string) float64 {
	return c.V.GetFloat64(key)
}

func (c *Config) GetFloat64Default(key string, defVal float64) float64 {
	return cast.ToFloat64(c.GetDefault(key, defVal))
}

func (c *Config) GetInt(key string) int {
	return c.V.GetInt(key)
}

func (c *Config) GetIntDefault(key string, defVal int) int {
	return cast.ToInt(c.GetDefault(key, defVal))
}

func (c *Config) GetInt64(key string) int64 {
	return c.V.GetInt64(key)
}

func (c *Config) GetInt64Default(key string, defVal int64) int64 {
	return cast.ToInt64(c.GetDefault(key, defVal))
}

func (c *Config) GetStrSlice(key string) []string {
	return c.V.GetStringSlice(key)
}

func (c *Config) GetStrMap(key string) map[string]any {
	return c.V.GetStringMap(key)
}

func (c *Config) GetStrMapStr(key string) map[string]string {
	return c.V.GetStringMapString(key)
}

func (c *Config) GetIntSlice(key string) []int {
	return c.V.GetIntSlice(key)
}

func (c *Config) Set(key string, val any) {
	c.V.Set(key, val)
}

func (c *Config) IsSet(key string) bool {
	return c.V.IsSet(key)
}
